home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / xsharp21.zip / DRAWTEX.ASM < prev    next >
Assembly Source File  |  1992-07-05  |  18KB  |  417 lines

  1. ; Draws all pixels in the specified scan line, with the pixel colors
  2. ; taken from the specified texture map.  Uses approach of pre-stepping
  3. ; 1/2 pixel into the source image and rounding to the nearest source
  4. ; pixel at each step, so that texture maps will appear reasonably similar
  5. ; at all angles.  This routine is specific to 320-pixel-wide planar
  6. ; (non-Chain4) 256-color modes, such as mode X, which is a planar
  7. ; (non-chain4) 256-color mode with a resolution of 320x240.
  8. ; C near-callable as:
  9. ;     void ScanOutLine(EdgeScan * LeftEdge, EdgeScan * RightEdge);
  10. ;
  11. ; Tested with TASM 3.0.
  12. ;
  13. ; The following C code is functionally equivalent to the assembler code:
  14.  
  15.         comment $ ;*****************************************************
  16.  
  17. /* Texture-map-draw the scan line between two edges. */
  18. void ScanOutLine(EdgeScan * LeftEdge, EdgeScan * RightEdge)
  19. {
  20.    Fixedpoint SourceX;
  21.    Fixedpoint SourceY;
  22.    int DestX = LeftEdge->DestX;
  23.    int DestXMax = RightEdge->DestX;
  24.    Fixedpoint DestWidth;
  25.    Fixedpoint SourceStepX, SourceStepY;
  26.  
  27.    /* Nothing to do if fully X clipped */
  28.    if ((DestXMax <= ClipMinX) || (DestX >= ClipMaxX)) {
  29.       return;
  30.    }
  31.  
  32.    if ((DestXMax - DestX) <= 0) {
  33.       return;  /* nothing to draw */
  34.    }
  35.  
  36.    SourceX = LeftEdge->SourceX;
  37.    SourceY = LeftEdge->SourceY;
  38.  
  39.    /* Width of destination scan line, for scaling. Note: because this is an
  40.       integer-based scaling, it can have a total error of as much as nearly
  41.       one pixel. For more precise scaling, also maintain a fixed-point DestX
  42.       in each edge, and use it for scaling. If this is done, it will also
  43.       be necessary to nudge the source start coordinates to the right by an
  44.       amount corresponding to the distance from the the real (fixed-point)
  45.       DestX and the first pixel (at an integer X) to be drawn) */
  46.    DestWidth = INT_TO_FIXED(DestXMax - DestX);
  47.  
  48.    /* Calculate source steps that correspond to each dest X step (across
  49.       the scan line) */
  50.    SourceStepX = FixedDiv(RightEdge->SourceX - SourceX, DestWidth);
  51.    SourceStepY = FixedDiv(RightEdge->SourceY - SourceY, DestWidth);
  52.  
  53.    /* Advance 1/2 step in the stepping direction, to space scanned pixels
  54.       evenly between the left and right edges. (There's a slight inaccuracy
  55.       in dividing negative numbers by 2 by shifting rather than dividing,
  56.       but the inaccuracy is in the least significant bit, and we'll just
  57.       live with it.) */
  58.    SourceX += SourceStepX >> 1;
  59.    SourceY += SourceStepY >> 1;
  60.  
  61.    /* Clip right edge if necssary */
  62.    if (DestXMax > ClipMaxX)
  63.       DestXMax = ClipMaxX;
  64.  
  65.    /* Clip left edge if necssary */
  66.    if (DestX < ClipMinX) {
  67.       SourceX += FixedMul(SourceStepX, INT_TO_FIXED(ClipMinX - DestX));
  68.       SourceY += FixedMul(SourceStepY, INT_TO_FIXED(ClipMinX - DestX));
  69.       DestX = ClipMinX;
  70.    }
  71.  
  72.    /* Scan across the destination scan line, updating the source image
  73.       position accordingly */
  74.    for (; DestX<DestXMax; DestX++) {
  75.    
  76.       /* Get the currently mapped pixel out of the image and draw it to
  77.          the screen */
  78.       WritePixelX(DestX, DestY,
  79.             GET_IMAGE_PIXEL(TexMapBits, TexMapWidth,
  80.             ROUND_FIXED_TO_INT(SourceX), ROUND_FIXED_TO_INT(SourceY)) );
  81.  
  82.       /* Point to the next source pixel */
  83.       SourceX += SourceStepX;
  84.       SourceY += SourceStepY;
  85.    }
  86. }
  87.         commentend $ ;*****************************************************
  88.  
  89. SC_INDEX equ    03c4h   ;Sequence Controller Index
  90. MAP_MASK equ    02h     ;index in SC of Map Mask register
  91. SCREEN_SEG equ  0a000h  ;segment of display memory in mode X
  92. SCREEN_WIDTH equ 80     ;width of screen in bytes from one scan line
  93.                         ; to the next
  94.  
  95.         .model  small
  96.         .data
  97.         extrn   _TexMapBits:word, _TexMapWidth:word, _DestY:word
  98.         extrn   _CurrentPageBase:word, _ClipMinX:word
  99.         extrn   _ClipMinY:word, _ClipMaxX:word, _ClipMaxY:word
  100.  
  101. ; Describes the current location and stepping, in both the source and
  102. ; the destination, of an edge. Mirrors structure in DRAWTEXP.C.
  103. EdgeScan struc
  104. Direction dw    ?       ;through edge list; 1 for a right edge (forward
  105.                         ; through vertex list), -1 for a left edge (backward
  106.                         ; through vertex list)
  107. RemainingScans dw ?     ;height left to scan out in dest
  108. CurrentEnd dw   ?       ;vertex # of end of current edge
  109. SourceX dd      ?       ;X location in source for this edge
  110. SourceY dd      ?       ;Y location in source for this edge
  111. SourceStepX dd  ?       ;X step in source for Y step in dest of 1
  112. SourceStepY dd  ?       ;Y step in source for Y step in dest of 1
  113.                         ;variables used for all-integer Bresenham's-type
  114.                         ; X stepping through the dest, needed for precise
  115.                         ; pixel placement to avoid gaps
  116. DestX   dw      ?       ;current X location in dest for this edge
  117. DestXIntStep dw ?       ;whole part of dest X step per scan-line Y step
  118. DestXDirection dw ?     ;-1 or 1 to indicate which way X steps (left/right)
  119. DestXErrTerm dw ?       ;current error term for dest X stepping
  120. DestXAdjUp dw   ?       ;amount to add to error term per scan line move
  121. DestXAdjDown dw ?       ;amount to subtract from error term when the
  122.                         ; error term turns over
  123. EdgeScan ends
  124.  
  125. Parms   struc
  126.           dw      2 dup(?) ;return address & pushed BP
  127. LeftEdge  dw      ?        ;pointer to EdgeScan structure for left edge
  128. RightEdge dw      ?        ;pointer to EdgeScan structure for right edge
  129. Parms   ends
  130.  
  131. ;Offsets from BP in stack frame of local variables.
  132. lSourceX        equ     -4      ;current X coordinate in source image
  133. lSourceY        equ     -8      ;current Y coordinate in source image
  134. lSourceStepX    equ     -12     ;X step in source image for X dest step of 1
  135. lSourceStepY    equ     -16     ;Y step in source image for X dest step of 1
  136. lXAdvanceByOne  equ     -18     ;used to step source pointer 1 pixel
  137.                                 ; incrementally in X
  138. lXBaseAdvance   equ     -20     ;use to step source pointer minimum number of
  139.                                 ; pixels incrementally in X
  140. lYAdvanceByOne  equ     -22     ;used to step source pointer 1 pixel
  141.                                 ; incrementally in Y
  142. lYBaseAdvance   equ     -24     ;use to step source pointer minimum number of
  143.                                 ; pixels incrementally in Y
  144. LOCAL_SIZE      equ     24      ;total size of local variables
  145.  
  146.         .code
  147.         extrn   _FixedMul:near, _FixedDiv:near
  148.  
  149.         align   2
  150. ToScanDone:
  151.         jmp     ScanDone
  152.  
  153.         public  _ScanOutLine
  154.         align   2
  155. _ScanOutLine    proc    near
  156.         push    bp              ;preserve caller's stack frame
  157.         mov     bp,sp           ;point to our stack frame
  158.         sub     sp,LOCAL_SIZE   ;allocate space for local variables
  159.         push    si              ;preserve caller's register variables
  160.         push    di
  161.  
  162. ; Nothing to do if destination is fully X clipped.
  163.  
  164.         mov     di,[bp].RightEdge
  165.         mov     si,[di].DestX
  166.         cmp     si,[_ClipMinX]
  167.         jle     ToScanDone      ;right edge is to left of clip rect, so done
  168.         mov     bx,[bp].LeftEdge
  169.         mov     dx,[bx].DestX
  170.         cmp     dx,[_ClipMaxX]
  171.         jge     ToScanDone      ;left edge is to right of clip rect, so done
  172.         sub     si,dx           ;destination fill width
  173.         jle     ToScanDone      ;null or negative full width, so done
  174.  
  175.         mov     ax,word ptr [bx].SourceX        ;initial source X coordinate
  176.         mov     word ptr [bp].lSourceX,ax
  177.         mov     ax,word ptr [bx].SourceX+2
  178.         mov     word ptr [bp].lSourceX+2,ax
  179.  
  180.         mov     ax,word ptr [bx].SourceY        ;initial source Y coordinate
  181.         mov     word ptr [bp].lSourceY,ax
  182.         mov     ax,word ptr [bx].SourceY+2
  183.         mov     word ptr [bp].lSourceY+2,ax
  184.  
  185. ; Calculate source steps that correspond to each 1-pixel destination X step
  186. ; (across the destination scan line).
  187.  
  188.         push    si              ;push dest X width, in fixedpoint form
  189.         sub     ax,ax
  190.         push    ax              ;push 0 as fractional part of dest X width
  191.         mov     ax,word ptr [di].SourceX
  192.         sub     ax,word ptr [bp].lSourceX       ;low word of source X width
  193.         mov     dx,word ptr [di].SourceX+2
  194.         sbb     dx,word ptr [bp].lSourceX+2     ;high word of source X width
  195.         push    dx              ;push source X width, in fixedpoint form
  196.         push    ax
  197.         call    _FixedDiv       ;scale source X width to dest X width
  198.         add     sp,8            ;clear parameters from stack
  199.         mov     word ptr [bp].lSourceStepX,ax   ;remember source X step for
  200.         mov     word ptr [bp].lSourceStepX+2,dx ; 1-pixel destination X step
  201.         mov     cx,1            ;assume source X advances non-negative
  202.         and     dx,dx           ;which way does source X advance?
  203.         jns     SourceXNonNeg   ;non-negative
  204.         neg     cx              ;negative
  205.         cmp     ax,0            ;is the whole step exactly an integer?
  206.         jz      SourceXNonNeg   ;yes
  207.         inc     dx              ;no, truncate to integer in the direction of
  208.                                 ; 0, because otherwise we'll end up with a
  209.                                 ; whole step of 1-too-large magnitude
  210. SourceXNonNeg:
  211.         mov     [bp].lXAdvanceByOne,cx  ;amount to add to source pointer to
  212.                                         ; move by one in X
  213.         mov     [bp].lXBaseAdvance,dx   ;minimum amount to add to source
  214.                                         ; pointer to advance in X each time
  215.                                         ; the dest advances one in X
  216.  
  217.         push    si              ;push dest Y height, in fixedpoint form
  218.         sub     ax,ax
  219.         push    ax              ;push 0 as fractional part of dest Y height
  220.         mov     ax,word ptr [di].SourceY
  221.         sub     ax,word ptr [bp].lSourceY       ;low word of source Y height
  222.         mov     dx,word ptr [di].SourceY+2
  223.         sbb     dx,word ptr [bp].lSourceY+2     ;high word of source Y height
  224.         push    dx              ;push source Y height, in fixedpoint form
  225.         push    ax
  226.         call    _FixedDiv       ;scale source Y height to dest X width
  227.         add     sp,8            ;clear parameters from stack
  228.         mov     word ptr [bp].lSourceStepY,ax   ;remember source Y step for
  229.         mov     word ptr [bp].lSourceStepY+2,dx ; 1-pixel destination X step
  230.         mov     cx,[_TexMapWidth] ;assume source Y advances non-negative
  231.         and     dx,dx           ;which way does source Y advance?
  232.         jns     SourceYNonNeg   ;non-negative
  233.         neg     cx              ;negative
  234.         cmp     ax,0            ;is the whole step exactly an integer?
  235.         jz      SourceYNonNeg   ;yes
  236.         inc     dx              ;no, truncate to integer in the direction of
  237.                                 ; 0, because otherwise we'll end up with a
  238.                                 ; whole step of 1-too-large magnitude
  239. SourceYNonNeg:
  240.         mov     [bp].lYAdvanceByOne,cx  ;amount to add to source pointer to
  241.                                         ; move by one in Y
  242.         mov     ax,[_TexMapWidth]       ;minimum distance skipped in source
  243.         imul    dx                      ; image bitmap when Y steps (ignoring
  244.         mov     [bp].lYBaseAdvance,ax   ; carry from the fractional part)
  245.  
  246. ; Advance 1/2 step in the stepping direction, to space scanned pixels evenly
  247. ; between the left and right edges. (There's a slight inaccuracy in dividing
  248. ; negative numbers by 2 by shifting rather than dividing, but the inaccuracy
  249. ; is in the least significant bit, and we'll just live with it.)
  250.  
  251.         mov     ax,word ptr [bp].lSourceStepX
  252.         mov     dx,word ptr [bp].lSourceStepX+2
  253.         sar     dx,1
  254.         rcr     ax,1
  255.         add     word ptr [bp].lSourceX,ax
  256.         adc     word ptr [bp].lSourceX+2,dx
  257.  
  258.         mov     ax,word ptr [bp].lSourceStepY
  259.         mov     dx,word ptr [bp].lSourceStepY+2
  260.         sar     dx,1
  261.         rcr     ax,1
  262.         add     word ptr [bp].lSourceY,ax
  263.         adc     word ptr [bp].lSourceY+2,dx
  264.  
  265. ; Clip right edge if necessary.
  266.  
  267.         mov     si,[di].DestX
  268.         cmp     si,[_ClipMaxX]
  269.         jl      RightEdgeClipped
  270.         mov     si,[_ClipMaxX]
  271. RightEdgeClipped:
  272.  
  273. ; Clip left edge if necssary
  274.  
  275.         mov     bx,[bp].LeftEdge
  276.         mov     di,[bx].DestX
  277.         cmp     di,[_ClipMinX]
  278.         jge     LeftEdgeClipped
  279.  
  280. ; Left clipping is necessary; advance the source accordingly
  281.  
  282.         neg     di
  283.         add     di,[_ClipMinX]  ;ClipMinX - DestX
  284.                                 ;first, advance the source in X
  285.         push    di              ;push ClipMinX - DestX, in fixedpoint form
  286.         sub     ax,ax
  287.         push    ax              ;push 0 as fractional part of ClipMinX-DestX
  288.         push    word ptr [bp].lSourceStepX+2
  289.         push    word ptr [bp].lSourceStepX
  290.         call    _FixedMul       ;total source X stepping in clipped area
  291.         add     sp,8            ;clear parameters from stack
  292.         add     word ptr [bp].lSourceX,ax   ;step the source X past clipping
  293.         adc     word ptr [bp].lSourceX+2,dx
  294.                                 ;now advance the source in Y
  295.         push    di              ;push ClipMinX - DestX, in fixedpoint form
  296.         sub     ax,ax
  297.         push    ax              ;push 0 as fractional part of ClipMinX-DestX
  298.         push    word ptr [bp].lSourceStepY+2
  299.         push    word ptr [bp].lSourceStepY
  300.         call    _FixedMul       ;total source Y stepping in clipped area
  301.         add     sp,8            ;clear parameters from stack
  302.         add     word ptr [bp].lSourceY,ax   ;step the source Y past clipping
  303.         adc     word ptr [bp].lSourceY+2,dx
  304.         mov     di,[_ClipMinX]  ;start X coordinate in dest after clipping
  305. LeftEdgeClipped:
  306.  
  307. ; Calculate actual clipped destination drawing width.
  308.  
  309.         sub     si,di
  310.  
  311. ; Scan across the destination scan line, updating the source image position
  312. ; accordingly.
  313.  
  314. ; Point to the initial source image pixel, adding 0.5 to both X and Y so that
  315. ; we can truncate to integers from now on but effectively get rounding.
  316.  
  317.         add     word ptr [bp].lSourceY,8000h    ;add 0.5
  318.         mov     ax,word ptr [bp].lSourceY+2
  319.         adc     ax,0
  320.         mul     [_TexMapWidth]   ;initial scan line in source image
  321.         add     word ptr [bp].lSourceX,8000h    ;add 0.5
  322.         mov     bx,word ptr [bp].lSourceX+2 ;offset into source scan line
  323.         adc     bx,ax            ;initial source offset in source image
  324.         add     bx,[_TexMapBits] ;DS:BX points to the initial image pixel
  325.  
  326. ; Point to initial destination pixel.
  327.  
  328.         mov     ax,SCREEN_SEG
  329.         mov     es,ax
  330.         mov     ax,SCREEN_WIDTH
  331.         mul     [_DestY] ;offset of initial dest scan line
  332.         mov     cx,di   ;initial destination X
  333.         shr     di,1
  334.         shr     di,1    ;X/4 = offset of pixel in scan line
  335.         add     di,ax   ;offset of pixel in page
  336.         add     di,[_CurrentPageBase] ;offset of pixel in display memory
  337.                         ;ES:DI now points to the first destination pixel
  338.  
  339.         and     cl,011b ;CL = pixel's plane
  340.         mov     al,MAP_MASK
  341.         mov     dx,SC_INDEX
  342.         out     dx,al   ;point the SC Index register to the Map Mask
  343.         mov     al,11h  ;one plane bit in each nibble, so we'll get carry
  344.                         ; automatically when going from plane 3 to plane 0
  345.         shl     al,cl   ;set the bit for the first pixel's plane to 1
  346.  
  347. ; If source X step is negative, change over to working with non-negative
  348. ; values.
  349.  
  350.         cmp     word ptr [bp].lXAdvanceByOne,0
  351.         jge     SXStepSet
  352.         neg     word ptr [bp].lSourceStepX
  353.         not     word ptr [bp].lSourceX
  354. SXStepSet:
  355.  
  356. ; If source Y step is negative, change over to working with non-negative
  357. ; values.
  358.  
  359.         cmp     word ptr [bp].lYAdvanceByOne,0
  360.         jge     SYStepSet
  361.         neg     word ptr [bp].lSourceStepY
  362.         not     word ptr [bp].lSourceY
  363. SYStepSet:
  364.  
  365. ; At this point:
  366. ;       AL = initial pixel's plane mask
  367. ;       BX = pointer to initial image pixel
  368. ;       SI = # of pixels to fill
  369. ;       DI = pointer to initial destination pixel
  370.  
  371.         mov     dx,SC_INDEX+1   ;point to SC Data; Index points to Map Mask
  372.  
  373. TexScanLoop:
  374.  
  375. ; Set the Map Mask for this pixel's plane, then draw the pixel.
  376.  
  377.         out     dx,al
  378.         mov     ah,[bx]         ;get image pixel
  379.         mov     es:[di],ah      ;set image pixel
  380.  
  381. ; Point to the next source pixel.
  382.  
  383.         add     bx,[bp].lXBaseAdvance   ;advance the minimum # of pixels in X
  384.         mov     cx,word ptr [bp].lSourceStepX
  385.         add     word ptr [bp].lSourceX,cx ;step the source X fractional part
  386.         jnc     NoExtraXAdvance           ;didn't turn over; no extra advance
  387.         add     bx,[bp].lXAdvanceByOne    ;did turn over; advance X one extra
  388. NoExtraXAdvance:
  389.  
  390.         add     bx,[bp].lYBaseAdvance   ;advance the minimum # of pixels in Y
  391.         mov     cx,word ptr [bp].lSourceStepY
  392.         add     word ptr [bp].lSourceY,cx ;step the source Y fractional part
  393.         jnc     NoExtraYAdvance           ;didn't turn over; no extra advance
  394.         add     bx,[bp].lYAdvanceByOne    ;did turn over; advance Y one extra
  395. NoExtraYAdvance:
  396.  
  397. ; Point to the next destination pixel, by cycling to the next plane, and
  398. ; advancing to the next address if the plane wraps from 3 to 0.
  399.  
  400.         rol     al,1
  401.         adc     di,0
  402.  
  403. ; Continue if there are any more dest pixels to draw.
  404.  
  405.         dec     si
  406.         jnz     TexScanLoop
  407.  
  408. ScanDone:
  409.         pop     di              ;restore caller's register variables
  410.         pop     si
  411.         mov     sp,bp           ;deallocate local variables
  412.         pop     bp              ;restore caller's stack frame
  413.         ret
  414. _ScanOutLine    endp
  415.  
  416.         end
  417.